-- 
-- Author:      name
-- DateTime:    2018-04-24 15:25:18
-- Description: 一些全局工具函数


local lfs = require "lfs"
local cjson = require "cjson"

local table = table
local math = math
local math_random = math.random
local table_insert = table.insert
local table_remove = table.remove
local table_sort = table.sort




----file
--取文件名(带后缀)
function get_file_names(str)
    return str:match("^.+/(.+)$")
end

--取文件名(不带后缀)
function get_file_name(str)
    local strName = get_file_names(str)    
    return strName:match("(.+)%.")
end

--取文件路径
--str: abc/abc/file.lua
--return abc/abc/
function get_root_path(str)
    return str:match("^.+%/")
end

--取文件后缀
function get_file_suffix(str)
    return str:match("^.+(%..+)$")
end

--打开目录
--path 文件夹路径
--suffix 文件类型后缀
--callback 回调
function open_dir(path, suffix, callback)    
    local attr = assert(lfs.attributes(path))
    if attr.mode == 'directory' then
        for f in lfs.dir(path) do
            if f ~= '.' and f ~= '..' then
                local file_suffix = get_file_suffix(f)
                if not suffix or file_suffix == suffix then
                    -- local fpath = path.."/"..f
                    -- local attr = assert(lfs.attributes(fpath))
                    -- if attr.mode == 'directory' then
                    --     open_dir(fpath, suffix, callback)
                    -- else
                        pcall(callback, f)
                    -- end
                end
            end
        end
    else
        pcall(callback, path)
    end
end

--取目录下目录列表文件列表
--path 文件夹路径
--suffix 文件类型后缀
function get_file_list(path, suffix)
    -- local file_list = {}
    -- open_dir(path, suffix, function(file_name, fpath)
    --     table_insert(file_list, file_name)
    --     -- print("fpath__", fpath)
    -- end)
    -- return file_list

    local file_list = {}
    local attr = assert(lfs.attributes(path))
    if attr.mode ~= 'directory' then
        return file_list
    end   
    for f in lfs.dir(path) do
        if f:find(".*") and f ~= '.' and f ~= '..' then
            table_insert(file_list, f)
        end
    end    
    return file_list
end

--创建文件夹
-- lfs.mkdir(path)


--table 按key大小排序
--small_first=true 从小到到
function table_sort_by_key(tb, small_first)
    local arr= {}
    for k,v in pairs(tb) do 
        table_insert(arr, {k=k,v=v})
    end
    if #arr == 0 then 
        return {}
    end
    local sort_func = function (a, b)
        if small_first then 
            return a.k < b.k
        else
            return a.k > b.k --从大到小
        end
    end   
    table_sort(arr, sort_func)
  
    return arr
end

--排列
--list 一个列表
--返回 所有数排列
function get_permutation(list)
    local res = {}
    local function permute(a,k)
        local len = #a
        if(len == k) then
            local b = {}
            for i,j in pairs(a) do
                 b[i] = j
             end
            table_insert(res,b)
        else
            for i=k, len do
                a[i], a[k] = a[k], a[i]
                permute(a,k+1)
                a[i], a[k] = a[k], a[i]
            end
        end
    end
    permute(list,1)
    return res
end

--组合
--返回 数组中选n个元素的组合
function get_combination(tb, n)
    -- 从长度为m的数组中选n个元素的组合 https://www.cnblogs.com/ksir16/p/8041457.html
    local len = #tb
    if n > len then
        return {}
    end    
    local meta = {}
    -- init meta data
    for i=1, len do
        if i <= n then
            table_insert(meta, 1)
        else
            table_insert(meta, 0)
        end
    end
    local result = {}
    -- 记录一次组合
    local tmp = {}
    for i=1, len do
        if meta[i] == 1 then
            table_insert(tmp, tb[i])
        end
    end
    table_insert(result, tmp)
    while true do
        -- 前面连续的0
        local zero_count = 0
        for i=1, len-n do
            if meta[i] == 0 then
                zero_count = zero_count + 1
            else
                break
            end
        end
        -- 前m-n位都是0，说明处理结束
        if zero_count == len-n then
            break
        end
        local idx
        for j=1, len-1 do
            -- 10 交换为 01
            if meta[j]==1 and meta[j+1] == 0 then
                meta[j], meta[j+1] = meta[j+1], meta[j]
                idx = j
                break
            end
        end
        -- 将idx左边所有的1移到最左边
        local k = idx-1
        local count = 0
        while count <= k do
            for i=k, 2, -1 do
                if meta[i] == 1 then
                    meta[i], meta[i-1] = meta[i-1], meta[i]
                end
            end
            count = count + 1
        end
        -- 记录一次组合
        local tmp = {}
        for i=1, len do
            if meta[i] == 1 then
                table_insert(tmp, tb[i])
            end
        end
        table_insert(result, tmp)
    end
    return result
end

--取当前本地ip
function get_ip_addr()
    local cmd = io.popen("ip addr")
    local str = cmd:read("*a")
    local ip = "0.0.0.0"
    io.close(cmd)
    local fun = function(a)
        local str = string.sub(a,1,string.find(a,'/')-1)
        print(str)
        if str~= '127.0.0.1' and not ip then 
            ip = str
            return
        end        
    end
    str = string.gsub(str,'%d*%.%d*%.%d*%.%d*/',fun)    
    print("__________________ip:",ip)
    return ip
end

--url解码
function decode_url(str)
    local s = str or ""
    s = string.gsub(s, '%%(%x%x)', function(h) return string.char(tonumber(h, 16)) end)
    return s
end

--url编码
function encode_url(str)
    local s = str or ""
    s = string.gsub(s, "([^%w%.%- ])", function(c) return string.format("%%%02X", string.byte(c)) end)
    return string.gsub(s, " ", "+")
end

--http透传
function http_pass(url,content,callback)
    if not httpc then 
        httpc = require "http.httpc"
        httpc.timeout = 3000
    end
    print("url_______:",url..content)
    local respheader = {}
    local status, body = httpc.get(url, content,respheader)
    callback(status,body)
end

--复制文件
function copy_file(source, destination)
    print("___copyfile___",source,destination)
    local sourcefile = io.open(source, "r")
    local destinationfile = io.open(destination, "w")
    if not destinationfile then
        return
    end
    destinationfile:write(sourcefile:read("*all"))
    sourcefile:close()
    destinationfile:close()
end 


-- 2016-08-23 10:41:02 转成时间截 xxxxxx
function string_time( date )
    local Y = string.sub(date,1,4)
    local M = string.sub(date,6,7)
    local D = string.sub(date,9,10)
    local H = string.sub(date,12,13)
    local MM = string.sub(date,15,16)
    local SS = string.sub(date,18,19)
    local dt1 = os.time{year=Y,month=M,day=D,hour=H,min=MM,sec=SS}
    return dt1
end
--时间截转日期
--local date = "" .. os.date("%Y-%m-%d %H:%M:%S", 1489549082)

--取日期
function get_date(time)
    time = time or os.time()
    return os.date("%Y-%m-%d",time)
end

function get_hour(time)
    time = time or os.time()
    return os.date("%H:%M:%S", time)
end

--是否是今天的时间
function is_today(timestamp)
    local today = os.date("*t")
    local secondOfToday = os.time({day=today.day, month=today.month,year=today.year, hour=0, minute=0, second=0})
    if timestamp >= secondOfToday and timestamp < secondOfToday + 24 * 60 * 60 then
        return true
    else
        return false
    end
end

--两个时间是否同一天
function is_same_day(time1, time2)   
    if get_date(time1) == get_date(time2) then
        return true
    else
        return false
    end
end

--- cjson序列化会出现NULL值, 可以通过cjson.null比较，清除
function clear_json_null(obj, null_v)
    if obj and type(obj) == "table" then
        for k, v in pairs(obj) do
            if v == cjson.null or v == "null" then
                obj[k] = null_v
            elseif type(v) == "table" then
                clear_json_null(v, null_v)
            end
        end
    end
    return obj
end

--读取文件
function read_file(path)
    local fstr = nil
    local fd = io.open(path, "r")
    if fd then
        fstr = fd:read("*a")
        fd:close()
    end
    return fstr
end

function read_lines(f, callback)
    local fd = io.open(f, "r")
    if fd then
        for line in fd:lines() do
            pcall(callback, line)
        end
        fd:close()
    end
end

function read_all_lines(f, callback)
    local fd = io.open(f, "r")
    if fd then
        local all_lines = fd:read("*all")
        pcall(callback, all_lines)
        fd:close()
    end
end

--加载json文件
function load_json_file(path)
    local fd = io.open(path, "r")
    if fd then
        local all_lines = fd:read("*all")
        fd:close()
        local ok, result = pcall(cjson.decode, all_lines)
        if not ok then
            print('load json path faild:'..path..' err:'..tostring(result))
        elseif result then
            return clear_json_null(result, '')
        end
        
        return nil        
    end
end

--加载lua文件
function load_lua_file(path)
    -- print("_______load_lua_file___",path)
    local fd = io.open(path, "r")
    if fd then
        local source = fd:read("*all")
        fd:close()
        local func, err = load(source, "@"..path, "bt")        
        if not func then
            print("__1__load_lua_file__error",path, err)
            return 
        end
        local ok, data = pcall(func)
        if not ok then
            print("__2__load_lua_file__error",path, data)
            return 
        end
        return data        
    end
end

--取文件的修改时间
function get_file_time(file)
    return lfs.attributes(file,"change") or 0
end

--4舍5入 
--digit:位数
function rounding(num, digit)
    digit = digit or 1
    num = num / digit
    return (num > 0 and math.floor(num + 0.5) or math.ceil(num - 0.5)) * digit
end

--回调的好手
function handler(obj, method)
    return function(...)
        if not method then 
            print("___error__obj___",obj:getName())
        end
        return method(obj, ...)
    end
end

--克隆
function clone(object)
    local lookup_table = {}
    local function _copy(object)
        if type(object) ~= "table" then
            return object
        elseif lookup_table[object] then
            return lookup_table[object]
        end
        local new_table = {}
        lookup_table[object] = new_table
        for key, value in pairs(object) do
            new_table[_copy(key)] = _copy(value)
        end
        return setmetatable(new_table, getmetatable(object))
    end
    return _copy(object)
end